
<!doctype html>
<html lang="en" class="no-js">
  <head>
    
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      
      
      
      
        <link rel="prev" href="../">
      
      
        <link rel="next" href="../live-demo/">
      
      
      <link rel="icon" href="../../assets/images/favicon.png">
      <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.20">
    
    
      
        <title>Overview - Robot Scheduling Docs</title>
      
    
    
      <link rel="stylesheet" href="../../assets/stylesheets/main.e53b48f4.min.css">
      
        
        <link rel="stylesheet" href="../../assets/stylesheets/palette.06af60db.min.css">
      
      


    
    
      
    
    
      
        
        
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
        <style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
      
    
    
      <link rel="stylesheet" href="../../styles.css">
    
    <script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
    
      

    
    
    
  </head>
  
  
    
    
      
    
    
    
    
    <body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="cyan">
  
    
    <input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
    <input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
    <label class="md-overlay" for="__drawer"></label>
    <div data-md-component="skip">
      
        
        <a href="#overview" class="md-skip">
          Skip to content
        </a>
      
    </div>
    <div data-md-component="announce">
      
    </div>
    
    
      

  

<header class="md-header md-header--shadow" data-md-component="header">
  <nav class="md-header__inner md-grid" aria-label="Header">
    <a href="../" title="Robot Scheduling Docs" class="md-header__button md-logo" aria-label="Robot Scheduling Docs" data-md-component="logo">
      
  
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>

    </a>
    <label class="md-header__button md-icon" for="__drawer">
      
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
    </label>
    <div class="md-header__title" data-md-component="header-title">
      <div class="md-header__ellipsis">
        <div class="md-header__topic">
          <span class="md-ellipsis">
            Robot Scheduling Docs
          </span>
        </div>
        <div class="md-header__topic" data-md-component="header-topic">
          <span class="md-ellipsis">
            
              Overview
            
          </span>
        </div>
      </div>
    </div>
    
      
        <form class="md-header__option" data-md-component="palette">
  
    
    
    
    <input class="md-option" data-md-color-media="" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="cyan"  aria-label="深色模式"  type="radio" name="__palette" id="__palette_0">
    
      <label class="md-header__button md-icon" title="深色模式" for="__palette_1" hidden>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m17.75 4.09-2.53 1.94.91 3.06-2.63-1.81-2.63 1.81.91-3.06-2.53-1.94L12.44 4l1.06-3 1.06 3zm3.5 6.91-1.64 1.25.59 1.98-1.7-1.17-1.7 1.17.59-1.98L15.75 11l2.06-.05L18.5 9l.69 1.95zm-2.28 4.95c.83-.08 1.72 1.1 1.19 1.85-.32.45-.66.87-1.08 1.27C15.17 23 8.84 23 4.94 19.07c-3.91-3.9-3.91-10.24 0-14.14.4-.4.82-.76 1.27-1.08.75-.53 1.93.36 1.85 1.19-.27 2.86.69 5.83 2.89 8.02a9.96 9.96 0 0 0 8.02 2.89m-1.64 2.02a12.08 12.08 0 0 1-7.8-3.47c-2.17-2.19-3.33-5-3.49-7.82-2.81 3.14-2.7 7.96.31 10.98 3.02 3.01 7.84 3.12 10.98.31"/></svg>
      </label>
    
  
    
    
    
    <input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="indigo" data-md-color-accent="cyan"  aria-label="亮色模式"  type="radio" name="__palette" id="__palette_1">
    
      <label class="md-header__button md-icon" title="亮色模式" for="__palette_0" hidden>
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 7a5 5 0 0 1 5 5 5 5 0 0 1-5 5 5 5 0 0 1-5-5 5 5 0 0 1 5-5m0 2a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0-7 2.39 3.42C13.65 5.15 12.84 5 12 5s-1.65.15-2.39.42zM3.34 7l4.16-.35A7.2 7.2 0 0 0 5.94 8.5c-.44.74-.69 1.5-.83 2.29zm.02 10 1.76-3.77a7.131 7.131 0 0 0 2.38 4.14zM20.65 7l-1.77 3.79a7.02 7.02 0 0 0-2.38-4.15zm-.01 10-4.14.36c.59-.51 1.12-1.14 1.54-1.86.42-.73.69-1.5.83-2.29zM12 22l-2.41-3.44c.74.27 1.55.44 2.41.44.82 0 1.63-.17 2.37-.44z"/></svg>
      </label>
    
  
</form>
      
    
    
      <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
    
    
      <div class="md-header__option">
  <div class="md-select">
    
    <button class="md-header__button md-icon" aria-label="Select language">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m12.87 15.07-2.54-2.51.03-.03A17.5 17.5 0 0 0 14.07 6H17V4h-7V2H8v2H1v2h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2zm-2.62 7 1.62-4.33L19.12 17z"/></svg>
    </button>
    <div class="md-select__inner">
      <ul class="md-select__list">
        
          <li class="md-select__item">
            <a href="../../overview/" hreflang="zh" class="md-select__link">
              中文
            </a>
          </li>
        
          <li class="md-select__item">
            <a href="./" hreflang="en" class="md-select__link">
              English
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</div>
    
    
      
      
        <label class="md-header__button md-icon" for="__search">
          
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
        </label>
        <div class="md-search" data-md-component="search" role="dialog">
  <label class="md-search__overlay" for="__search"></label>
  <div class="md-search__inner" role="search">
    <form class="md-search__form" name="search">
      <input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
      <label class="md-search__icon md-icon" for="__search">
        
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
        
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
      </label>
      <nav class="md-search__options" aria-label="Search">
        
        <button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
          
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
        </button>
      </nav>
      
    </form>
    <div class="md-search__output">
      <div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
        <div class="md-search-result" data-md-component="search-result">
          <div class="md-search-result__meta">
            Initializing search
          </div>
          <ol class="md-search-result__list" role="presentation"></ol>
        </div>
      </div>
    </div>
  </div>
</div>
      
    
    
      <div class="md-header__source">
        <a href="https://gitee.com/Jimmy-chen-zheng/robot-interface-demo.git" title="Go to repository" class="md-source" data-md-component="source">
  <div class="md-source__icon md-icon">
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
  </div>
  <div class="md-source__repository">
    Gitee
  </div>
</a>
      </div>
    
  </nav>
  
</header>
    
    <div class="md-container" data-md-component="container">
      
      
        
          
        
      
      <main class="md-main" data-md-component="main">
        <div class="md-main__inner md-grid">
          
            
              
              <div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
                <div class="md-sidebar__scrollwrap">
                  <div class="md-sidebar__inner">
                    



  

<nav class="md-nav md-nav--primary md-nav--integrated" aria-label="Navigation" data-md-level="0">
  <label class="md-nav__title" for="__drawer">
    <a href="../" title="Robot Scheduling Docs" class="md-nav__button md-logo" aria-label="Robot Scheduling Docs" data-md-component="logo">
      
  
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>

    </a>
    Robot Scheduling Docs
  </label>
  
    <div class="md-nav__source">
      <a href="https://gitee.com/Jimmy-chen-zheng/robot-interface-demo.git" title="Go to repository" class="md-source" data-md-component="source">
  <div class="md-source__icon md-icon">
    
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
  </div>
  <div class="md-source__repository">
    Gitee
  </div>
</a>
    </div>
  
  <ul class="md-nav__list" data-md-scrollfix>
    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Dashboard
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
    
  
  
  
    <li class="md-nav__item md-nav__item--active">
      
      <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
      
      
        
      
      
        <label class="md-nav__link md-nav__link--active" for="__toc">
          
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

          <span class="md-nav__icon md-icon"></span>
        </label>
      
      <a href="./" class="md-nav__link md-nav__link--active">
        
  
  
  <span class="md-ellipsis">
    Overview
    
  </span>
  

      </a>
      
        

<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
  
  
  
    
  
  
    <label class="md-nav__title" for="__toc">
      <span class="md-nav__icon md-icon"></span>
      Table of contents
    </label>
    <ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
      
        <li class="md-nav__item">
  <a href="#0-recommended-reading-order" class="md-nav__link">
    <span class="md-ellipsis">
      0. Recommended Reading Order
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#sec-what-why" class="md-nav__link">
    <span class="md-ellipsis">
      1. Robot Management Platform (What / Why)
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#sec-mono-to-micro" class="md-nav__link">
    <span class="md-ellipsis">
      2. From Monolith to Microservices
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#sec-architecture" class="md-nav__link">
    <span class="md-ellipsis">
      3. Architecture Overview
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#sec-phases" class="md-nav__link">
    <span class="md-ellipsis">
      4. Project Phases &amp; Milestones
    </span>
  </a>
  
</li>
      
        <li class="md-nav__item">
  <a href="#sec-openapi-stability" class="md-nav__link">
    <span class="md-ellipsis">
      5. OpenAPI Wrapping &amp; Stability Governance
    </span>
  </a>
  
</li>
      
    </ul>
  
</nav>
      
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../live-demo/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Live Demo
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../config-nacos/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Configuration Center (Nacos)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../observability/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Observability (SkyWalking)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../stability-sentinel/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Stability (Sentinel)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../mq-async/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Async (RabbitMQ)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../docker-deploy/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Containerized Deployment (Docker)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../loadtest-jmeter/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Load Test (JMeter)
    
  </span>
  

      </a>
    </li>
  

    
      
      
  
  
  
  
    <li class="md-nav__item">
      <a href="../issues-rca/" class="md-nav__link">
        
  
  
  <span class="md-ellipsis">
    Issues·Root Cause·Fixes
    
  </span>
  

      </a>
    </li>
  

    
  </ul>
</nav>
                  </div>
                </div>
              </div>
            
            
          
          
            <div class="md-content" data-md-component="content">
              <article class="md-content__inner md-typeset">
                
                  



<h1 id="overview">Overview<a class="headerlink" href="#overview" title="Permanent link">&para;</a></h1>
<blockquote>
<p>This chapter gives the overall path and reading order.<br />
Use the mini-TOC on the right; click any item in “Recommended Reading Order” to jump to its section.</p>
</blockquote>
<h2 id="0-recommended-reading-order">0. Recommended Reading Order<a class="headerlink" href="#0-recommended-reading-order" title="Permanent link">&para;</a></h2>
<ol>
<li><a href="#sec-what-why">Robot Management Platform (What / Why)</a> — background &amp; goals  </li>
<li><a href="#sec-mono-to-micro">From Monolith to Microservices</a> — migration strategy &amp; boundaries  </li>
<li><a href="#sec-architecture">Architecture Overview</a> — components &amp; trade-offs  </li>
<li><a href="#sec-phases">Project Phases &amp; Milestones</a> — break big goals into small steps  </li>
<li><a href="#sec-openapi-stability">OpenAPI Wrapping &amp; Stability Governance</a> — interface governance &amp; resilience  </li>
<li><a href="#sec-slo">Service Level Objectives (SLO)</a> — target metrics &amp; continuous improvement</li>
</ol>
<hr />
<h2 id="sec-what-why">1. Robot Management Platform (What / Why)<a class="headerlink" href="#sec-what-why" title="Permanent link">&para;</a></h2>
<p><strong>What</strong><br />
- A unified entry for multiple vendors’ robots (cleaning, patrol, delivery, etc.).<br />
- Normalize vendor OpenAPIs; provide orchestration, scheduling, monitoring, and safety guards.</p>
<p><strong>Why</strong><br />
- <strong>Integration pain</strong>: different auth/signing, request/response formats, error semantics.<br />
- <strong>Stability</strong>: rate-limits, retries, backoff, circuit-breakers, graceful degradation.<br />
- <strong>Ops</strong>: full-link tracing, metrics, logs; issue → root cause → fix loop.<br />
- <strong>Delivery</strong>: one-click multi-env delivery with Docker Compose.</p>
<hr />
<h2 id="sec-mono-to-micro">2. From Monolith to Microservices<a class="headerlink" href="#sec-mono-to-micro" title="Permanent link">&para;</a></h2>
<h3 id="summary">Summary<a class="headerlink" href="#summary" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Module</th>
<th>Key points</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Background / Pain</strong></td>
<td>Monolith validated quickly; as scale grew, releases had a wide blast radius and configs became scattered.</td>
</tr>
<tr>
<td><strong>Goal</strong></td>
<td>Smooth migration with near-zero UX impact; <strong>minute-level rollback</strong>.</td>
</tr>
<tr>
<td><strong>Key Design</strong></td>
<td><strong>Gateway</strong>: <code>/external/gs/**</code>; <strong>Nacos</strong>: registry/config (multi-env); <strong>Docker Compose</strong>: <strong>one-click multi-container</strong> delivery.</td>
</tr>
<tr>
<td><strong>Trade-offs</strong></td>
<td>DTOs extracted to <code>ruoyi-api-robot</code>; controllers <strong>slimmed</strong>; logic pushed down to <code>GsOpenApiServiceImpl</code>.</td>
</tr>
</tbody>
</table>
<h3 id="metrics-results">Metrics &amp; Results<a class="headerlink" href="#metrics-results" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th style="text-align: right;">Target / Baseline</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Cold start → ready</strong></td>
<td style="text-align: right;">≤ <strong>12 min</strong></td>
<td>Compose (incl. first-run SQL) to bring up a fresh environment.</td>
</tr>
<tr>
<td><strong>Rollback time</strong></td>
<td style="text-align: right;">≤ <strong>5 min</strong></td>
<td>Minute-level rollback after the split.</td>
</tr>
<tr>
<td><strong>p95 latency</strong></td>
<td style="text-align: right;"><strong>≈ 6 ms</strong></td>
<td>Baseline 100 QPS (Dry-Run); P99 ≈ 9–10 ms; Error=0.</td>
</tr>
<tr>
<td><strong>Release window</strong></td>
<td style="text-align: right;">Shorter</td>
<td>Impact scope shrinks after splitting services.</td>
</tr>
<tr>
<td><strong>One-click delivery</strong></td>
<td style="text-align: right;">Compose + volumes + first-run SQL</td>
<td>Fresh env ready ≤ 12 min.</td>
</tr>
</tbody>
</table>
<h3 id="retro">Retro<a class="headerlink" href="#retro" title="Permanent link">&para;</a></h3>
<ul>
<li>Ship first, evolve later; unify <strong>resource names / rules / error body / log fields</strong>.</li>
</ul>
<hr />
<h2 id="sec-architecture">3. Architecture Overview<a class="headerlink" href="#sec-architecture" title="Permanent link">&para;</a></h2>
<blockquote>
<p>Shape: RuoYi-Cloud microservices (Gateway + business), Nacos for registry/config, RabbitMQ for async (see the Async page), MySQL/Redis for data &amp; cache, SkyWalking for observability loop, Nginx for static frontends.</p>
</blockquote>
<h3 id="1-system-diagram">1) System Diagram<a class="headerlink" href="#1-system-diagram" title="Permanent link">&para;</a></h3>
<p><img alt="Robot Management Platform Architecture" src="/assets/04-architecture.png" /></p>
<p><strong>Relations</strong>
- <strong>Ingress</strong>: <code>User/Browser → Nginx → Spring Cloud Gateway</code> (<code>/api/**</code> routes)<br />
- <strong>Business</strong>: <code>RuoYi-System</code> (Auth/ACL) and <code>RuoYi-Robot Adapter</code> (OpenAPI aggregation)<br />
- <strong>Registry/Config</strong>: via <strong>Nacos</strong> (multi-environment)<br />
- <strong>Data</strong>: <code>MySQL</code> (business data) and <code>Redis</code> (cache)<br />
- <strong>Async</strong>: <code>RabbitMQ</code> (topic→queue→DLQ, manual-ack, idempotency)<br />
- <strong>Observability</strong>: <code>SkyWalking</code> (trace/log/metrics stitched by <code>traceId</code>)<br />
- <strong>Delivery</strong>: Docker Compose for multi-env one-click bring-up</p>
<hr />
<h2 id="sec-phases">4. Project Phases &amp; Milestones<a class="headerlink" href="#sec-phases" title="Permanent link">&para;</a></h2>
<ul>
<li>Phase-1… (keep your original list; content unchanged, English wording aligned)  </li>
<li>Emphasize increments: gateway governance → async → observability → stability → delivery.</li>
</ul>
<hr />
<h2 id="sec-openapi-stability">5. OpenAPI Wrapping &amp; Stability Governance<a class="headerlink" href="#sec-openapi-stability" title="Permanent link">&para;</a></h2>
<h3 id="summary_1">Summary<a class="headerlink" href="#summary_1" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Module</th>
<th>Key points</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Background / Pain</strong></td>
<td>Vendor APIs have unstable RT/errors; upstream callers easily get dragged down.</td>
</tr>
<tr>
<td><strong>Goals</strong></td>
<td>Unify auth/retry/idempotency/trace; <strong>two-layer protection</strong> (Gateway + method level); read-mostly paths support <strong>cached fallback</strong>.</td>
</tr>
<tr>
<td><strong>Design</strong></td>
<td><code>GsOpenApiServiceImpl</code> + <code>@SentinelResource</code> (resource names aligned with Nacos rules); Nacos-pushed <code>Flow/Degrade</code> rules; <br> <code>RestTemplate</code>: <strong>timeouts/connection pool</strong> tuned, <strong>auto-retry disabled</strong>.</td>
</tr>
<tr>
<td><strong>Trade-offs</strong></td>
<td><strong>Gateway vs. App who blocks first</strong>: relax Gateway limits in tests to observe breakpoints — <strong>prefer rate-limit first</strong>, then degrade/circuit-break as needed.</td>
</tr>
</tbody>
</table>
<h3 id="metrics-results-examples">Metrics &amp; Results (examples)<a class="headerlink" href="#metrics-results-examples" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Metric</th>
<th style="text-align: right;">Target / Baseline</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Burst handling</strong></td>
<td style="text-align: right;"><strong>429 fast-fail</strong></td>
<td>Gateway/Sentinel returns immediately to protect downstream.</td>
</tr>
<tr>
<td><strong>p95 latency</strong></td>
<td style="text-align: right;">‹value› ms</td>
<td>Fill with your test result; read-heavy paths should hit cache first.</td>
</tr>
<tr>
<td><strong>Degrade policy</strong></td>
<td style="text-align: right;">Last good data</td>
<td>Read endpoints return cached/snapshotted data (TTL-controlled).</td>
</tr>
<tr>
<td><strong>Protection layers</strong></td>
<td style="text-align: right;">Gateway first</td>
<td>Gateway rate-limit before app-level circuit-break; <code>@SentinelResource</code> as method-level safety net.</td>
</tr>
<tr>
<td><strong>Retry/Timeout</strong></td>
<td style="text-align: right;">Auto-retry disabled</td>
<td><code>RestTemplate</code> connection/read timeouts and pooling to avoid cascades.</td>
</tr>
</tbody>
</table>
<h3 id="retro_1">Retro<a class="headerlink" href="#retro_1" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Rate-limit before circuit-break</strong>; unify <strong>error body/log fields</strong> for faster diagnosis.</li>
</ul>
<hr />
<h1 id="service-level-objectives-slo">Service Level Objectives (SLO)<a class="headerlink" href="#service-level-objectives-slo" title="Permanent link">&para;</a></h1>
<blockquote>
<p>Scope: Spring Cloud Gateway + Robot Service.<br />
Window: 28 days (monthly).<br />
Success definition: Count as success when the HTTP status is not 5xx and the business <code>code==0</code>; <strong>intentional 429 (rate limiting) is not counted as a failure</strong> and is tracked separately for capacity and threshold tuning.<br />
Latency: by default, measure the duration from <strong>Gateway ingress → response sent</strong>.</p>
</blockquote>
<hr />
<h2 id="slo-english">📈 SLO (English)<a class="headerlink" href="#slo-english" title="Permanent link">&para;</a></h2>
<h3 id="1-slo-table">1) SLO Table<a class="headerlink" href="#1-slo-table" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Journey / API</th>
<th>SLI</th>
<th>Target</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Status query <code>GET /external/gs/status/**</code></td>
<td>Success ≥ 99.9%</td>
<td>Monthly</td>
<td>Gateway rate-limit first; single-instance stable QPS × 0.7 headroom</td>
</tr>
<tr>
<td></td>
<td>P95 &lt; 300ms (P99 &lt; 800ms)</td>
<td>Monthly</td>
<td>Client typically retries with backoff 1–2 times</td>
</tr>
<tr>
<td>Map list <code>GET /maps/list/**</code></td>
<td>Success ≥ 99.9%</td>
<td>Monthly</td>
<td>Read-heavy; cache/replica</td>
</tr>
<tr>
<td></td>
<td>P95 &lt; 400ms</td>
<td>Monthly</td>
<td>API baseline</td>
</tr>
<tr>
<td>Task dispatch (async acceptance) <code>POST /external/gs/task/**</code></td>
<td>Acceptance success ≥ 99.5%</td>
<td>Monthly (~3.6h budget)</td>
<td>Count success only if <strong>persisted + enqueued</strong>; idempotency key <code>taskId</code></td>
</tr>
<tr>
<td></td>
<td>Acceptance P95 &lt; 1s</td>
<td>Monthly</td>
<td>Synchronous “accepted” only; <strong>execution ACK not in this SLO</strong></td>
</tr>
<tr>
<td>WebSocket updates</td>
<td>Reconnect 99% &lt; 3s</td>
<td>Monthly</td>
<td>Auto-reconnect; <code>stale</code> triggers alert</td>
</tr>
</tbody>
</table>
<h3 id="2-sli-definitions">2) SLI Definitions<a class="headerlink" href="#2-sli-definitions" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Success rate</strong> = (requests − HTTP 5xx − business failures) ÷ requests; business failure per unified <code>code</code>.  </li>
<li><strong>Latency</strong>: P50/P95/P99 from <strong>gateway ingress to response</strong>; add service spans if needed.  </li>
<li><strong>Async acceptance</strong>: HTTP 202/200 <strong>and</strong> persisted+enqueued = success (requires app metric).  </li>
<li><strong>WebSocket recovery</strong>: disconnect to “receiving again” (heartbeat/subscription ack).</li>
</ul>
<h3 id="3-protection-thresholds-aligned-with-sentinel">3) Protection thresholds (aligned with Sentinel)<a class="headerlink" href="#3-protection-thresholds-aligned-with-sentinel" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Slow-call threshold</strong> <code>τ = min(1000ms, 1.2 × current baseline P95)</code>  </li>
<li><strong>Window</strong> 10s; <strong>minimum samples</strong> ≥ 20; <strong>slow-call ratio</strong> ≥ 50% → open circuit  </li>
<li><strong>Open</strong> 30s; <strong>Half-open probes</strong> 5–10  </li>
<li><strong>Ingress rate-limit</strong> on <code>/external/gs/**</code> at Gateway (returns 429)</li>
</ul>
<h3 id="4-alerting-actions">4) Alerting &amp; Actions<a class="headerlink" href="#4-alerting-actions" title="Permanent link">&para;</a></h3>
<ul>
<li><strong>Error budget</strong>: 99.9% target ⇒ 0.1% monthly  </li>
<li><strong>Burn rate alerts</strong> (either condition): 1h &gt; 10% budget ⇒ P1 (auto degrade/limit); 6h &gt; 20% ⇒ P1 escalate (rollback / remove unhealthy instance)  </li>
<li><strong>Release guard</strong>: within 15min after release, if P95/P99 worsens and error &gt; threshold ⇒ pause/rollback  </li>
<li><strong>Traffic control</strong>: ramp Gateway quotas 5%→30%→50%→100%; if worse, staged circuit with stable fallback</li>
</ul>
<h3 id="5-observability-sources">5) Observability &amp; Sources<a class="headerlink" href="#5-observability-sources" title="Permanent link">&para;</a></h3>
<p>SkyWalking traces/metrics; structured logs with <code>traceId</code> + 429/503/timeout fields; Nacos groups for rules with gray &amp; rollback.</p>
<h3 id="6-exceptions">6) Exceptions<a class="headerlink" href="#6-exceptions" title="Permanent link">&para;</a></h3>
<p>Execution SLA of long-running async tasks is <strong>out of scope</strong> here; external-network incidents are labeled for review, not forcibly excluded.</p>












                
              </article>
            </div>
          
          
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
        </div>
        
          <button type="button" class="md-top md-icon" data-md-component="top" hidden>
  
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
  Back to top
</button>
        
      </main>
      
        <footer class="md-footer">
  
    
      
      <nav class="md-footer__inner md-grid" aria-label="Footer" >
        
          
          <a href="../" class="md-footer__link md-footer__link--prev" aria-label="Previous: Dashboard">
            <div class="md-footer__button md-icon">
              
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
            </div>
            <div class="md-footer__title">
              <span class="md-footer__direction">
                Previous
              </span>
              <div class="md-ellipsis">
                Dashboard
              </div>
            </div>
          </a>
        
        
          
          <a href="../live-demo/" class="md-footer__link md-footer__link--next" aria-label="Next: Live Demo">
            <div class="md-footer__title">
              <span class="md-footer__direction">
                Next
              </span>
              <div class="md-ellipsis">
                Live Demo
              </div>
            </div>
            <div class="md-footer__button md-icon">
              
              <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
            </div>
          </a>
        
      </nav>
    
  
  <div class="md-footer-meta md-typeset">
    <div class="md-footer-meta__inner md-grid">
      <div class="md-copyright">
  
    <div class="md-copyright__highlight">
      © 2025 陈峥 Jimmy Chen · <a href="/legal/license/">MIT License</a>
    </div>
  
  
    Made with
    <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
      Material for MkDocs
    </a>
  
</div>
      
        
<div class="md-social">
  
    
    
    
    
    <a href="https://github.com/JimmyZChen" target="_blank" rel="noopener" title="GitHub" class="md-social__link">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34-.46-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.87 1.52 2.34 1.07 2.91.83.09-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.92 0-1.11.38-2 1.03-2.71-.1-.25-.45-1.29.1-2.64 0 0 .84-.27 2.75 1.02.79-.22 1.65-.33 2.5-.33s1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02.55 1.35.2 2.39.1 2.64.65.71 1.03 1.6 1.03 2.71 0 3.82-2.34 4.66-4.57 4.91.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2"/></svg>
    </a>
  
    
    
    
    
    <a href="https://gitee.com/Jimmy-chen-zheng" target="_blank" rel="noopener" title="Gitee" class="md-social__link">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.984 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm6.09 5.333c.328 0 .593.266.592.593v1.482a.594.594 0 0 1-.593.592H9.777c-.982 0-1.778.796-1.778 1.778v5.63c0 .327.266.592.593.592h5.63c.982 0 1.778-.796 1.778-1.778v-.296a.593.593 0 0 0-.592-.593h-4.15a.59.59 0 0 1-.592-.592v-1.482a.593.593 0 0 1 .593-.592h6.815c.327 0 .593.265.593.592v3.408a4 4 0 0 1-4 4H5.926a.593.593 0 0 1-.593-.593V9.778a4.444 4.444 0 0 1 4.445-4.444h8.296Z"/></svg>
    </a>
  
    
    
    
    
    <a href="mailto:chenzheng2024xm@163.com" target="_blank" rel="noopener" title="Email" class="md-social__link">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m20 8-8 5-8-5V6l8 5 8-5m0-2H4c-1.11 0-2 .89-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2"/></svg>
    </a>
  
    
    
    
    
    <a href="https://www.linkedin.com/in/jimmy-chen-74a8182b8/" target="_blank" rel="noopener" title="LinkedIn" class="md-social__link">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93zM6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37z"/></svg>
    </a>
  
</div>
      
    </div>
  </div>
</footer>
      
    </div>
    <div class="md-dialog" data-md-component="dialog">
      <div class="md-dialog__inner md-typeset"></div>
    </div>
    
    
    
      
      <script id="__config" type="application/json">{"base": "../..", "features": ["navigation.instant", "navigation.sections", "content.code.copy", "content.image.zoom", "content.image.lightbox", "toc.integrate", "navigation.footer", "navigation.top"], "search": "../../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
    
    
      <script src="../../assets/javascripts/bundle.f55a23d4.min.js"></script>
      
        <script src="../../move-palette.js"></script>
      
    
  </body>
</html>